package com.lin.pay.wx.service;

import com.google.gson.Gson;
import com.lin.common.constant.CustomerServiceConstant;
import com.lin.common.error.CustomRuntimeException;
import com.lin.common.error.ErrorCode;
import com.lin.common.utils.HttpClientUtils;
import com.lin.config.SpringContextIniter;
import com.lin.pay.wx.WXPayConstant;
import com.lin.pay.wx.sdk.WXPay;
import com.lin.pay.wx.sdk.WXPayConfig;
import com.lin.pay.wx.sdk.WXPayConstants;
import com.lin.pay.wx.sdk.WxPayConfigImpl;
import com.lin.pay.wx.utils.WxMsgUtils;
import com.lin.pay.wx.vo.AccessTokenResult;
import com.lin.pay.wx.vo.OpenidResult;
import com.lin.pay.wx.vo.TicketResult;
import com.lin.properties.PayProperties;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class WxServiceImpl implements WxService {
    /**
     * 日志.
     */
    private static final Logger log = LoggerFactory.getLogger(WxServiceImpl.class);

    @Autowired
    private PayProperties payProperties;
    //    @Value("${cs.wx.notify-url}")
//    private String notifyUrl;
//
//    @Value("${cs.wx.appid:wx3559c6993a353d7b}")
//    private String appid;
//    @Value("${cs.wx.secret}")
//    private String secret;
//    @Value("${cs.wx.url}")
//    private String wxurl;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public Map pay(String openid, BigDecimal trxAmt, Long orderNo, Long payOrderNo) throws CustomRuntimeException {
        final WXPayConfig pc = SpringContextIniter.getBean(WxPayConfigImpl.class);
        try {
            WXPay pay = new WXPay(pc, payProperties.getWx().get(PayProperties.WX_NOTIFY_URL), false, false);
            Map<String, String> reqData = initReqData(openid, payOrderNo, trxAmt);
            Map<String, String> resData = pay.unifiedOrder(reqData);
//            resData.put(WXPayConstant.OUT_TRADE_NO, payOrderNo);
            resData.put(WXPayConstant.SIGN_TYPE_FIELD, WXPayConstants.MD5);
            log.info(resData.toString());
            //设置JSAPI调起支付对应的参数并重新签名
            Map req = WxMsgUtils.buildWCPayRequest(resData, pc.getKey());
            log.info("build sign getBrandWCPayRequest: \n{}", req.toString());
            return req;
        } catch (Exception e) {
            log.error("error {}", e);
            throw new CustomRuntimeException(ErrorCode.PAY_FAIL, ErrorCode.PAY_FAIL.getMessage());
        }
    }

    @Override
    public OpenidResult getOpenId(String code) {
        String url = payProperties.getWx().get(PayProperties.WX_URL) + "/sns/oauth2/access_token?appid=" + payProperties.getWx().get(PayProperties.WX_APPID) + "&secret=" + payProperties.getWx().get(PayProperties.WX_SECRET) + "&code=" + code + "&grant_type=authorization_code";
        String result = HttpClientUtils.httpGet(url);
        Gson g = new Gson();
        OpenidResult or = g.fromJson(result, OpenidResult.class);
        return or;
    }

    @Override
    public String getAccessToken() {
        String url = payProperties.getWx().get(PayProperties.WX_URL) + "/cgi-bin/token?grant_type=client_credential&appid=" + payProperties.getWx().get(PayProperties.WX_APPID) + "&secret=" + payProperties.getWx().get(PayProperties.WX_SECRET);
        String result = HttpClientUtils.httpGet(url);
        Gson g = new Gson();
        AccessTokenResult atr = g.fromJson(result, AccessTokenResult.class);
        return atr.getAccess_token();
    }

    @Override
    public String getTicket() throws CustomRuntimeException {
        RBucket<String> rb = redissonClient.getBucket(CustomerServiceConstant.CS_WX_TICKET);
        String ticket = rb.get();
        if (StringUtils.isNotBlank(ticket)) {
            return ticket;
        } else {
            String token = getToken();
            if (StringUtils.isNotBlank(token)) {
                String url = payProperties.getWx().get(PayProperties.WX_URL) + "/cgi-bin/ticket/getticket?access_token=" + token + "&type=jsapi";
                log.info("微信ticket的url： {}", url);
                String result = HttpClientUtils.httpGet(url);
                Gson g = new Gson();
                TicketResult tr = g.fromJson(result, TicketResult.class);
                if (StringUtils.isBlank(tr.getTicket())) {
                    throw new CustomRuntimeException(ErrorCode.ACCESS_TOKEN_NULL, ErrorCode.ACCESS_TOKEN_NULL.getMessage());
                }
                rb.set(tr.getTicket(), CustomerServiceConstant.CS_WX_TICKET_TIMEOUT, TimeUnit.SECONDS);
                return tr.getTicket();
            } else {
                throw new CustomRuntimeException(ErrorCode.ACCESS_TOKEN_NULL, ErrorCode.ACCESS_TOKEN_NULL.getMessage());
            }
        }
    }

    @Override
    public String sha1sign(String signStr) throws CustomRuntimeException {
        String ticket = getTicket();
        return DigestUtils.sha1Hex(ticket + "&" + signStr);
    }

    private String getToken() {
        String url = payProperties.getWx().get(PayProperties.WX_URL) + "/cgi-bin/token?grant_type=client_credential&appid=" + payProperties.getWx().get(PayProperties.WX_APPID) + "&secret=" + payProperties.getWx().get(PayProperties.WX_SECRET);
        String result = HttpClientUtils.httpGet(url);
        Gson g = new Gson();
        AccessTokenResult atr = g.fromJson(result, AccessTokenResult.class);
        return atr.getAccess_token();
    }

    /**
     * 封装请求信息.
     *
     * @param trxAmt  交易金额.
     * @param orderNo
     * @return 返回封装内容.
     */
    private Map<String, String> initReqData(String openid, Long orderNo, BigDecimal trxAmt) {

        Map<String, String> reqData = new HashMap<>();
        reqData.put(WXPayConstant.BODY, "统一下单");
        reqData.put(WXPayConstant.ATTACH, "附加信息");
        reqData.put(WXPayConstant.OUT_TRADE_NO, String.valueOf(orderNo));
        reqData.put(WXPayConstant.TOTAL_FEE, String.valueOf(trxAmt));
        reqData.put(WXPayConstant.SPBILL_CREATE_IP, "127.0.0.1");
        reqData.put(WXPayConstant.TRADE_TYPE, "JSAPI");
        reqData.put(WXPayConstant.OPENID, openid);
        return reqData;
    }
}
